"""Json 协议解析器"""
from PyQt5.QtWidgets import QFileDialog

"""
{
  "format": {
    "frameHeader": {
      "description": "帧头，固定2字节",
      "default": "AA55",
      "length": "2"
    },
    "frameLength": {
      "description": "帧长度字段，包含自身占用的2字节，共2字节",
      "default": "10", // 或者指定一个默认值，如果适用的话
      "length": "2"
    },
    "sourceDeviceAddress": {
      "description": "源设备地址，1字节",
      "default": "00",
      "length": "1"
    },
    "destinationDeviceAddress": {
      "description": "目的设备地址，1字节",
      "default": "",
      "length": "1"
    },
    "messageBody": {
      "description": "消息体，N字节，长度由帧长度字段决定",
      "default": "", // 可能不适合设置默认值，因为长度可变
      "length": "variable"
    },
    "crc": {
      "description": "循环冗余校验码，用于错误检测，2字节",
      // 注意：CRC通常需要根据数据计算，不宜设置默认值
      "default": "",
      "length": "2"
    },
    "frameTail": {
      "description": "帧尾，固定2字节，用于标识帧结束",
      "default": "FFAA",
      "length": "2"
    },
    "dataprotocol":{
      "description": "数据解析协议",
      "default": "1",
      "length": "1"
    }
  }
}
"""

import json
from screen.LogControl.log_init import *


"""Json文件解析器"""
class JsonProtocol:
    def __init__(self):
        """
        初始化
        """
        self.log = Log_Config()                             #初始化日志管理器对象
        self.frame_header = None                            #帧头
        self.frame_length = None                            #帧长度
        self.source_device_address = None                   #源设备地址
        self.destination_device_address = None              #目的设备地址
        self.message_body = None                            #消息体
        self.crc = None                                     #CRC校验码
        self.frame_tail = None                              #帧尾
        self.dataprotocol = None                            #数据解析协议

    """获取JSON文件的路径"""
    def get_json_path(self):
        """
        选择JSON配置文件
        :return:文件路径
        """
        file_path = QFileDialog.getOpenFileName(None, "选择JSON文件", "", "*.json")
        if file_path:
            return file_path
        return None

    """加载Json文件"""
    def json_load(self, json_file_path):
        """
        导入JSON文件
        :param json_file_path:JSON文件的路径
        :return:None
        """
        try:
            #导入JSON文件
            with open(json_file_path, 'r', encoding='utf-8') as file:
                Json_config = json.load(file)

                #获取JSON文件中的配置信息
                if 'format' in Json_config:
                    self.frame_header = Json_config['format']['frameHeader']['default']                             #帧头 A5 5A
                    self.source_device_address = Json_config['format']['sourceDeviceAddress']['default']            #源设备地址 00
                    self.destination_device_address = Json_config['format']['destinationDeviceAddress']['default']  #目的设备地址 00
                    self.frame_tail = Json_config['format']['frameTail']['default']                                 #帧尾 5A A5
                    self.dataprotocol = Json_config['format']['dataprotocol']['default']                            #数据解析协议 1,2,3,4
                    self.frame_length = Json_config['format']['frameLength']['default']                             #默认十个字节，还需要加上消息体

                    #测试
                    print(f'帧头:{self.frame_header}')
                    print(f'源设备地址:{self.source_device_address}')
                    print(f'目的设备地址:{self.destination_device_address}')
                    print(f'帧尾:{self.frame_tail}')
                    print(f'数据解析协议:{self.dataprotocol}')
                    print(f'帧长度:{self.frame_length}')

                    return True
                else:
                    self.log.logger.error("JSON文件信息错误")
                    return False
        except json.JSONDecodeError:
            self.log.logger.error("JSON文件格式错误")
            return False

    """校验和方法"""
    def json_cheacksum(self, data:bytes):
        """
        校验函数
        :param data:参与计算的数据
        :return:返回校验的数据
        """
        POLYNOMIAL = 0xa001
        crc = 0xffff
        for byte in data:
            crc ^= byte
            for i in range(8):
                if crc & 1:
                    crc >>=1
                    crc ^= POLYNOMIAL
                else:
                    crc >>= 1
        return  (crc & 0xFFFF).to_bytes(2, byteorder='big')

    """打包帧"""
    def json_pack(self,params:bytes):
        """
        根据导入的协议构造指令
        :param params:包含指令的控制参数
        :return:状态信息或者打包完成的指令
        """
        #帧头
        frame_header = bytes.fromhex(self.frame_header)

        #帧长度
        length = int(int(self.frame_length) + len(params))
        frame_length = length.to_bytes(2, byteorder='big')

        #源设备地址
        source_device_address = bytes.fromhex(self.source_device_address)

        #目的设备地址
        destination_device_address = bytes.fromhex(self.destination_device_address)

        #消息体
        message_body = params

        #CRC校验码
        CRCCheaknum = self.json_cheacksum(frame_length+source_device_address+destination_device_address+message_body)

        #帧尾
        frame_tail = bytes.fromhex(self.frame_tail)

        #返回帧
        data = frame_header+frame_length+source_device_address+destination_device_address+message_body+CRCCheaknum+frame_tail
        return data

    """解析接收到的数据帧"""
    def json_unpack(self,data:bytes,size:int):
        """
        解析接收到的数据
        :param data:待解析的数据
        :param size:解析数据的长度
        :return:状态码或者解析完毕后的消息体
        """
        try:
            #帧长度获取
            two_bytes_length = data[2:4]
            length = int.from_bytes(two_bytes_length, byteorder='big', signed=False)            #获取2个字节的帧长度，大端序，无符号数据类型

            #数据长度不相等
            if size != length:
                self.log.logger.error("数据长度错误")
                return None

            #帧头错误
            if data[0:2] != bytes.fromhex(self.frame_header):
                self.log.logger.error("帧头错误")
                return None

            #地址错误
            if int(data[5]) != int(self.source_device_address,16):
                self.log.logger.error("地址错误")
                return None

            #CRC校验码
            if data[length-4:length-2] != self.json_cheacksum(data[2:length-4]):
                self.log.logger.error("CRC校验码错误")
                return None

            #帧尾错误
            if data[length-2:length] != bytes.fromhex(self.frame_tail):
                self.log.logger.error("帧尾错误")
                return None

            # 返回消息体
            return data[6:length-4]

        except Exception as e:
            self.log.logger.error(e)
            return None



